package file

import (
	"context"
	"fmt"
	"os"
	"path"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/service/attachment/model"
	"mall/service/attachment/rpc/internal/svc"
	"mall/service/attachment/rpc/internal/utils/errorhandler"
	"mall/service/attachment/rpc/types/attachment"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"

	// "github.com/sirupsen/logrus"
	"github.com/volatiletech/null/v8"
	"github.com/zeromicro/go-zero/core/logx"
)

type BackendCreateFileLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBackendCreateFileLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackendCreateFileLogic {
	return &BackendCreateFileLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BackendCreateFileLogic) BackendCreateFile(in *attachment.FileInfo) (*attachment.BaseUUIDResp, error) {
	// logrus.Info(fmt.Sprintf("BackendCreateFile: %+v", in))

	now := time.Now()
	gmtNow := modelx.GetGmtTime(now)
	file := &model.Attachment{
		PostStatus:       uint16(globalkey.AttachmentStatusPublish),
		PostDate:         now,
		PostDateGMT:      gmtNow,
		PostModifiedDate: now,
		PostModifiedGMT:  gmtNow,
	}
	if in.Type != nil && *in.Type == uint32(globalkey.AttachmentTypeDirectory) {
		var parentId uint64
		if in.ParentId != nil {
			parentId = *in.ParentId
		}
		if parentId == 0 {
			parentId = l.svcCtx.Config.NfsConf.UploadsId
		}
		parentDir, err := l.svcCtx.MediaFile.FindOne(l.ctx, parentId)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		parentPath := parentDir.Path
		if in.Filename != nil {
			file.PostName = strings.ToLower(strings.TrimSpace(*in.Filename))
		}
		if in.Path != nil {
			file.Path = strings.ToLower(strings.TrimSpace(*in.Path))
		} else if len(file.PostName) > 0 {
			file.Path = strings.ToLower(fmt.Sprintf("%s/%s", parentPath, file.PostName))
		}
		if len(file.Path) == 0 {
			return nil, errorx.NewInvalidArgumentError("file.directoryPathRequired")
		}

		filterMap := make(map[string]map[string][]any)
		filterMap[model.AttachmentColumns.Path] = map[string][]any{
			"equalTo": {file.Path},
		}
		filterMap[model.AttachmentColumns.PostParentID] = map[string][]any{
			"equalTo": {parentId},
		}
		_, count, err := l.svcCtx.MediaFile.GetList(l.ctx, model.M{}, 0, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if count > 0 {
			return nil, errorx.NewAlreadyExistsError("file.directoryPathAlreadyExists")
		}

		file.PostParentID = parentId
		file.PostType = uint16(globalkey.AttachmentTypeDirectory)
		if in.AltText != nil {
			file.PostTitle = strings.TrimSpace(*in.AltText)
		}
		if in.Excerpt != nil {
			file.PostExcerpt = strings.TrimSpace(*in.Excerpt)
		}
		if in.UserId != nil && len(strings.TrimSpace(*in.UserId)) > 0 {
			if i, err := strconv.ParseInt(strings.TrimSpace(*in.UserId), 10, 64); err == nil {
				file.PostAuthorID = uint64(i)
			}
		}
		err = l.svcCtx.MediaFile.Insert(l.ctx, nil, file, nil)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		dir := path.Join(l.svcCtx.Config.NfsConf.PathPrefix, file.Path)
		_, err = os.Stat(dir)
		if err != nil {
			if os.IsNotExist(err) {
				if err = os.MkdirAll(dir, 0775); err != nil {
					logx.Errorw("failed to create media directory", logx.Field("path", dir))
					return nil, errorx.NewInternalError("file.createDirectoryFailed")
				}
			} else {
				logx.Errorw("failed to parse media directory", logx.Field("path", dir))
			}
		}

		return &attachment.BaseUUIDResp{
			Id:  strconv.FormatUint(file.ID, 10),
			Msg: i18n.CreateSuccess,
		}, nil
	}

	if in.Filename != nil {
		file.PostName = strings.TrimSpace(*in.Filename)
	}
	if in.Path != nil {
		file.Path = strings.TrimSpace(*in.Path)
	}
	if in.Size != nil {
		file.Size = *in.Size
	}
	if in.Type != nil {
		file.PostType = uint16(*in.Type)
	} else {
		file.PostType = uint16(globalkey.AttachmentTypeLocalTempFile)
	}
	if in.MimeType != nil {
		file.PostMimeType = strings.TrimSpace(*in.MimeType)
	}
	if in.Md5 != nil {
		file.MD5 = strings.TrimSpace(*in.Md5)
	}
	if in.ParentId != nil && *in.ParentId > 0 {
		file.PostParentID = *in.ParentId
	} else {
		file.PostParentID = l.svcCtx.Config.NfsConf.UploadsId
	}
	if in.AltText != nil {
		file.PostTitle = strings.TrimSpace(*in.AltText)
	}
	if in.Excerpt != nil {
		file.PostExcerpt = strings.TrimSpace(*in.Excerpt)
	}
	if in.UserId != nil && len(strings.TrimSpace(*in.UserId)) > 0 {
		if i, err := strconv.ParseInt(strings.TrimSpace(*in.UserId), 10, 64); err == nil {
			file.PostAuthorID = uint64(i)
		}
	}
	if in.Status != nil {
		file.PostStatus = uint16(*in.Status)
	} else {
		file.PostStatus = uint16(globalkey.AttachmentStatusDraft)
	}

	rel := &model.AttachmentRel{}
	if len(in.Meta) > 0 {
		for _, m := range in.Meta {
			if m.Key == nil || len(strings.TrimSpace(*m.Key)) == 0 {
				continue
			}

			if m.Value == nil || len(strings.TrimSpace(*m.Value)) == 0 {
				continue
			}

			rel.Meta = append(rel.Meta, &model.AttachmentMetum{
				MetaKey:   strings.TrimSpace(*m.Key),
				MetaValue: null.StringFrom(strings.TrimSpace(*m.Value)),
			})
		}
	}

	err := l.svcCtx.MediaFile.Insert(l.ctx, nil, file, rel)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	return &attachment.BaseUUIDResp{
		Id:  strconv.FormatUint(file.ID, 10),
		Msg: i18n.CreateSuccess,
	}, nil
}
